package com.itheima.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Author itheima
 * @Date 2022/4/26 11:42
 * 事务切面类
 * 思考 ：
 * 1.搭建 3步骤：目标对象+切面类+织入
 * 2.切面类：切入点（找到要被增强的方法）+通知（增强逻辑的封装）
 */
@Component
@Aspect
public class TransactionAspect {

    //1.切入点： 通过表达式找到目标对象中的要被增强的方法 save
    @Pointcut("execution(* com.itheima.service..*.sa*(..))")
    public void myPoint() {
    }

    //2.通知：切面中增强逻辑的封装，具体就是 一个个方法而已
    //2.1前置通知 ：目标方法执行之前，前置通知会 执行

    /**
     * @Before(value表达式就是确定目标对象哪些方法要被增强) JoinPoint: 对save方法信息的封装
     */
    @Before("myPoint()")
    public void start(JoinPoint joinPoint) {
        System.out.println("前置通知：开启事务");
        //1.获取save方法类  UserServiceImpl
        Object target = joinPoint.getTarget();
        System.out.println("target = " + target.getClass().getName());
        //2.获取目标方法的方法名：save
        Signature signature = joinPoint.getSignature();
        System.out.println("signature = " + signature.getName());
        //3.获取目标方法的传入的参数：new User(1L, "tom")
        Object[] args = joinPoint.getArgs();
        System.out.println("args = " + Arrays.asList(args));

    }

    //2.2最终通知：提交事务
    @After("myPoint()")
    public void commit() {
        System.out.println("最终通知：提交事务");
    }

    //2.3环绕通知： 把目标方法save，立即把目标方法包裹起来

    /**
     * ProceedingJoinPoint extends JoinPoint 连接点（目标对象中方法），就是我们在save方法封装。
     * 注意：该参数只能在环绕通知中使用
     */
    @Around("myPoint()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知：包裹开始");
        //integer  res=userServiceImpl.save()
        Object res = joinPoint.proceed();
        System.out.println("环绕通知：包裹结束");
        return res;
    }

    //2.4返回通知：目标方法return之后，此时返回通知就会执行

    /**
     * return 1;
     * Integer res=1;
     */
    @AfterReturning(value = "myPoint()", returning = "res")
    public void afterReturning(Integer res) {
        System.out.println("返回通知:接收的返回的数据是" + res);
    }

    //2.5异常通知：目标方法执行过程，如果抛出异常，该异常通知 就会执行

    /**
     * Exception e=ArithmeticException接收抛出的异常
     */
    @AfterThrowing(value = "myPoint()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("异常通知:获取目标方法抛出的异常" + e);
    }
}
